{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the requests library for making HTTP requests\n",
    "import requests\n",
    "\n",
    "# Import the Path class from the pathlib module for handling file system paths\n",
    "from pathlib import Path\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pathlib import Path\n",
    "import requests\n",
    "\n",
    "# Check if the file \"ov_phi3_vision.py\" does not exist\n",
    "if not Path(\"ov_phi3_vision.py\").exists():\n",
    "    # If the file does not exist, download it from the specified URL\n",
    "    r = requests.get(url=\"https://raw.githubusercontent.com/openvinotoolkit/openvino_notebooks/latest/notebooks/phi-3-vision/ov_phi3_vision.py\")\n",
    "    # Write the content of the downloaded file to \"ov_phi3_vision.py\"\n",
    "    open(\"ov_phi3_vision.py\", \"w\").write(r.text)\n",
    "\n",
    "# Check if the file \"gradio_helper.py\" does not exist\n",
    "if not Path(\"gradio_helper.py\").exists():\n",
    "    # If the file does not exist, download it from the specified URL\n",
    "    r = requests.get(url=\"https://raw.githubusercontent.com/openvinotoolkit/openvino_notebooks/latest/notebooks/phi-3-vision/gradio_helper.py\")\n",
    "    # Write the content of the downloaded file to \"gradio_helper.py\"\n",
    "    open(\"gradio_helper.py\", \"w\").write(r.text)\n",
    "\n",
    "# Check if the file \"notebook_utils.py\" does not exist\n",
    "if not Path(\"notebook_utils.py\").exists():\n",
    "    # If the file does not exist, download it from the specified URL\n",
    "    r = requests.get(url=\"https://raw.githubusercontent.com/openvinotoolkit/openvino_notebooks/latest/utils/notebook_utils.py\")\n",
    "    # Write the content of the downloaded file to \"notebook_utils.py\"\n",
    "    open(\"notebook_utils.py\", \"w\").write(r.text)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the convert_phi3_model function from the ov_phi3_vision module\n",
    "from ov_phi3_vision import convert_phi3_model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "⌛ Phi-3-vision conversion started. Be patient, it may takes some time.\n",
      "⌛ Load Original model\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "82c1572d29dd478caad40c7d9a4cbe19",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Loading checkpoint shards:   0%|          | 0/2 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "✅ Original model successfully loaded\n",
      "⌛ Convert Input embedding model\n",
      "✅ Input embedding model successfully converted\n",
      "⌛ Convert Image embedding model\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\kinfeylo\\AppData\\Roaming\\Python\\Python311\\site-packages\\transformers\\modeling_utils.py:4481: FutureWarning: `_is_quantized_training_enabled` is going to be deprecated in transformers 4.39.0. Please use `model.hf_quantizer.is_trainable` instead\n",
      "  warnings.warn(\n",
      "C:\\Users\\kinfeylo\\AppData\\Roaming\\Python\\Python311\\site-packages\\transformers\\models\\clip\\modeling_clip.py:276: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!\n",
      "  if attn_weights.size() != (bsz * self.num_heads, tgt_len, src_len):\n",
      "C:\\Users\\kinfeylo\\AppData\\Roaming\\Python\\Python311\\site-packages\\transformers\\models\\clip\\modeling_clip.py:316: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!\n",
      "  if attn_output.size() != (bsz * self.num_heads, tgt_len, self.head_dim):\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "✅ Image embedding model successfully converted\n",
      "⌛ Convert Image projection model\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "You are not running the flash-attention implementation, expect numerical differences.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "✅ Image projection model successfully converted\n",
      "⌛ Convert Language model\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\kinfeylo\\AppData\\Roaming\\Python\\Python311\\site-packages\\transformers\\modeling_attn_mask_utils.py:114: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!\n",
      "  if (input_shape[-1] > 1 or self.sliding_window is not None) and self.is_causal:\n",
      "C:\\Users\\kinfeylo\\AppData\\Roaming\\Python\\Python311\\site-packages\\transformers\\modeling_attn_mask_utils.py:162: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!\n",
      "  if past_key_values_length > 0:\n",
      "C:\\Users\\kinfeylo\\.cache\\huggingface\\modules\\transformers_modules\\microsoft\\Phi-3-vision-128k-instruct\\6065b7a1a412feff7ac023149f65358b71334984\\modeling_phi3_v.py:143: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!\n",
      "  if seq_len > self.original_max_position_embeddings:\n",
      "c:\\Users\\kinfeylo\\.conda\\envs\\openvinodev\\Lib\\site-packages\\nncf\\torch\\dynamic_graph\\wrappers.py:86: TracerWarning: torch.tensor results are registered as constants in the trace. You can safely ignore this warning if you use this function to create tensors out of constant variables that would be the same every time you call this function. In any other case, this might cause the trace to be incorrect.\n",
      "  op1 = operator(*args, **kwargs)\n",
      "C:\\Users\\kinfeylo\\.cache\\huggingface\\modules\\transformers_modules\\microsoft\\Phi-3-vision-128k-instruct\\6065b7a1a412feff7ac023149f65358b71334984\\modeling_phi3_v.py:381: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!\n",
      "  if attn_weights.size() != (bsz, self.num_heads, q_len, kv_seq_len):\n",
      "C:\\Users\\kinfeylo\\.cache\\huggingface\\modules\\transformers_modules\\microsoft\\Phi-3-vision-128k-instruct\\6065b7a1a412feff7ac023149f65358b71334984\\modeling_phi3_v.py:388: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!\n",
      "  if attention_mask.size() != (bsz, 1, q_len, kv_seq_len):\n",
      "C:\\Users\\kinfeylo\\.cache\\huggingface\\modules\\transformers_modules\\microsoft\\Phi-3-vision-128k-instruct\\6065b7a1a412feff7ac023149f65358b71334984\\modeling_phi3_v.py:400: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!\n",
      "  if attn_output.size() != (bsz, self.num_heads, q_len, self.head_dim):\n",
      "c:\\Users\\kinfeylo\\.conda\\envs\\openvinodev\\Lib\\site-packages\\torch\\jit\\_trace.py:168: UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute won't be populated during autograd.backward(). If you indeed want the .grad field to be populated for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more informations. (Triggered internally at C:\\actions-runner\\_work\\pytorch\\pytorch\\builder\\windows\\pytorch\\build\\aten\\src\\ATen/core/TensorBody.h:494.)\n",
      "  if a.grad is not None:\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "✅ Language model successfully converted\n",
      "⌛ Weights compression with int4_sym mode started\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "816b35f60b5549c0a7a9939785b136e8",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Output()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
      ],
      "text/plain": []
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:nncf:Statistics of the bitwidth distribution:\n",
      "+----------------+-----------------------------+----------------------------------------+\n",
      "|   Num bits (N) | % all parameters (layers)   | % ratio-defining parameters (layers)   |\n",
      "+================+=============================+========================================+\n",
      "|              8 | 42% (54 / 129)              | 40% (53 / 128)                         |\n",
      "+----------------+-----------------------------+----------------------------------------+\n",
      "|              4 | 58% (75 / 129)              | 60% (75 / 128)                         |\n",
      "+----------------+-----------------------------+----------------------------------------+\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "6c56fbda6564497db8357f9379277314",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Output()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
      ],
      "text/plain": []
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "✅ Weights compression finished\n",
      "✅ Phi-3-vision model conversion finished. You can find results in model\\phi3-vision\\int4\n"
     ]
    }
   ],
   "source": [
    "# Import the Path class from the pathlib module for handling file system paths\n",
    "from pathlib import Path\n",
    "\n",
    "# Import the nncf library for model compression\n",
    "import nncf\n",
    "\n",
    "# Define the model ID for the Phi-3 vision model\n",
    "model_id = \"microsoft/Phi-3-vision-128k-instruct\"\n",
    "\n",
    "# Define the output directory for the compressed model\n",
    "out_dir = Path(\"model/phi3-vision/int4\")\n",
    "\n",
    "# Define the compression configuration for the model\n",
    "compression_configuration = {\n",
    "    \"mode\": nncf.CompressWeightsMode.INT4_SYM,  # Set the compression mode to INT4 symmetric\n",
    "    \"group_size\": 64,  # Set the group size for compression\n",
    "    \"ratio\": 0.6,  # Set the compression ratio\n",
    "}\n",
    "# Convert the Phi-3 model using the specified model ID, output directory, and compression configuration\n",
    "convert_phi3_model(model_id, out_dir, compression_configuration)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e7a5c72c7c5448af8da382f324f07d2d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Dropdown(description='Device:', index=1, options=('CPU', 'GPU', 'AUTO'), value='GPU')"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Import the device_widget function from the notebook_utils module\n",
    "from notebook_utils import device_widget\n",
    "\n",
    "# Create a device widget with the default device set to \"GPU\" and excluding \"NPU\"\n",
    "device = device_widget(default=\"GPU\", exclude=[\"NPU\"])\n",
    "\n",
    "# Display the device widget\n",
    "device\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the OvPhi3Vision class from the ov_phi3_vision module\n",
    "from ov_phi3_vision import OvPhi3Vision\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "WindowsPath('model/phi3-vision/int4')"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# The output directory for the compressed model\n",
    "out_dir"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize the OvPhi3Vision model with the specified output directory and device\n",
    "model = OvPhi3Vision(out_dir, device.value)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the requests library for making HTTP requests\n",
    "import requests\n",
    "\n",
    "# Import the Image class from the PIL (Pillow) library for image processing\n",
    "from PIL import Image\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Open an image file located at \"./imgs/demo.png\" using the PIL library\n",
    "image = Image.open(r\"./imgs/demo.png\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<PIL.PngImagePlugin.PngImageFile image mode=RGBA size=426x413>"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Display the opened image\n",
    "image\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Coding:\n",
      "To create a pie chart representing marks obtained in an exam, we can use the matplotlib library in Python. Here is a step-by-step guide on how to do it:\n",
      "\n",
      "\n",
      "\n",
      "1. First, import the necessary libraries. We need matplotlib for creating the pie chart and pandas for handling the data.\n",
      "\n",
      "\n",
      "```python\n",
      "import matplotlib.pyplot as plt\n",
      "import pandas as pd\n",
      "```\n",
      "\n",
      "2. Next, we need to create a DataFrame from the given data.\n",
      "```python\n",
      "data = {'subject': ['maths', 'physics', 'chemistry', 'english'], 'marks': [340, 300, 2000, 150]}\n",
      "df = pd.DataFrame(data)\n",
      "```\n",
      "3. Now, we can create the pie chart. We use the 'autop' parameter to display the percentage of each slice.\n",
      "```python\n",
      "plt = plt.pie(df['marks'], labels = df['subject'], autop=True, colors=['red','blue','yellow','green'])\n",
      "```\n",
      "4. Finally, we can display the chart and save it as a jpg file.\n",
      "```python\n",
      "plt.title('Marks obtained in an exam')\n",
      "plt.savefig('imgs/im-3-3-3.jpg')\n",
      "```\n",
      "\n",
      "This code will create a pie chart representing the marks obtained in an exam. The chart will be saved as 'im-3-3-3.jpg'.\n"
     ]
    }
   ],
   "source": [
    "# Import the AutoProcessor and TextStreamer classes from the transformers library\n",
    "from transformers import AutoProcessor, TextStreamer\n",
    "\n",
    "# Define the messages to be processed, including an image and a request to create Python code\n",
    "messages = [\n",
    "    {\"role\": \"user\", \"content\": \"<|image_1|>\\nPlease create Python code for image, and use plt to save the new picture under imgs/ and name it phi-3-vision.jpg.\"},\n",
    "]\n",
    "\n",
    "# Load the processor from the pretrained model specified by the output directory\n",
    "processor = AutoProcessor.from_pretrained(out_dir, trust_remote_code=True)\n",
    "\n",
    "# Apply the chat template to the messages to create a prompt for the model\n",
    "prompt = processor.tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)\n",
    "\n",
    "# Process the prompt and the image, returning the inputs as tensors\n",
    "inputs = processor(prompt, [image], return_tensors=\"pt\")\n",
    "\n",
    "# Define the generation arguments for the model\n",
    "generation_args = {\"max_new_tokens\": 3072, \"do_sample\": False, \"streamer\": TextStreamer(processor.tokenizer, skip_prompt=True, skip_special_tokens=True)}\n",
    "\n",
    "# Print a message indicating that the coding process is starting\n",
    "print(\"Coding:\")\n",
    "\n",
    "# Generate the model's output based on the inputs and generation arguments\n",
    "generate_ids = model.generate(**inputs, eos_token_id=processor.tokenizer.eos_token_id, **generation_args)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "openvinodev",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
